﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace AnimalWars2 
{
    public class Ball : MovableEntity
    {
        public BallState m_BallState;
        public float m_TopLimit = -120.0f;
        public float m_BottonLimit = 120.0f;
        public float m_LeftLimit = -78.0f;
        public float m_RightLimit = 78.0f;
        public float m_xDirection = 0; // < 0 = esquerda, > 0 = direita
        public float m_yDirection = 0; // < 0 = subindo, > 0 = descendo

        public GameTable m_GameTable;

        public Ball(GameTable GameTableRef, Texture2D Tex, Vector2 Pos, Vector2 Vel, BallState State) :
            base(GameTableRef.m_Game, Tex, Pos, Vel)
        {
            m_Accel = 1000.0f;
            m_MaxVel = 150.0f;
            m_Scale = 1.0f;
            m_Depth = 0.25f;
            m_BallState = State;
            m_oColor = Color.White;
            m_GameTable = GameTableRef;
        }

        private void VerticalCollision()
        {
            // verifica se bateu na parede lateral e inverte a direção da bola
            if (m_Pos.X <= m_LeftLimit || m_Pos.X >= m_RightLimit)
            {
                m_xDirection *= -1;
                m_Vel.X *= -1;
            }
        }

        private void MoveBall(ref Vector2 vMoveDir) 
        {
            vMoveDir.Y += m_yDirection;
            vMoveDir.X += m_xDirection;
        }

        private void StopTheBall()
        {
            m_BallState = BallState.Stopped;
            m_Vel = new Vector2(0.0f, 0.0f);

            if (m_yDirection > 0)
            {
                m_Pos.Y = m_TopLimit;
            }
            else
            {
                m_Pos.Y = m_BottonLimit;
            }
        }

        public BallDirection getDirection() 
        {
            if (m_yDirection < 0)
            {
                return BallDirection.Up;
            }
            else
            {
                return BallDirection.Down;
            }
        }

        public override Vector2 GetMoveDir()
        {
            Vector2 vMoveDir = Vector2.Zero;

            switch (m_BallState)
            {
                case BallState.Moving:
                    {
                        // verifica se a bola NAO chegou no limite superior ou inferior (+/-) PLAYER_AREA_SIZE
                        if ((getDirection() == BallDirection.Up && m_Pos.Y >= m_TopLimit - Constants.PLAYER_AREA_SIZE) // a bola esta subindo
                         || (getDirection() == BallDirection.Down && m_Pos.Y <= m_BottonLimit + Constants.PLAYER_AREA_SIZE)) // a bola esta descendo
                        {
                            BallCollisionDetection();
                            VerticalCollision();
                            MoveBall(ref vMoveDir);
                        }
                        else // parking
                        {
                            m_BallState = BallState.Parking;
                            m_yDirection *= -1;
                            m_Vel.Y *= -1;
                        }
                    }
                    break;
                case BallState.Parking:
                    {
                        // verifica se a bola saiu da área do player e para a bola
                        if ((getDirection() == BallDirection.Up && m_Pos.Y <= m_BottonLimit) // a bola esta voltando de baixo para cima
                         || (getDirection() == BallDirection.Down && m_Pos.Y >= m_TopLimit)) // a bola esta voltando de cima para baixo
                        {
                            StopTheBall();
                            vMoveDir = Vector2.Zero;
                        }
                        else
                        {
                            BallCollisionDetection();
                            VerticalCollision();
                            MoveBall(ref vMoveDir);
                        }
                    }

                    break;
            }

            return vMoveDir;
        }

        public Boolean DetectCollision(MovableEntity movableEntity)
        {
            if (Vector2.Distance(m_Pos, movableEntity.m_Pos) <= movableEntity.m_Size.X)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public Boolean BallCollisionDetection() 
        {
            foreach (Entity entity in m_GameTable.m_Entities)
            {
                if( (entity as Player) != null
                 && this.m_BallState == BallState.Parking )
                {
                    Player player = (Player) entity;

                    if (DetectCollision(player))
                    {
                        player.m_PlayerState = PlayerState.Stunned;
                    }
                }
                if (entity is Ball && entity != this)
                { 
                    Ball ball = (Ball) entity;

                    if ( ball.m_BallState != BallState.Stopped && DetectCollision(ball))
                    {
                        // as bolas tiverem a mesma direcao em Y apenas inverte a direcao em X
                        if (m_yDirection > 0 && ball.m_yDirection > 0 || m_yDirection < 0 && ball.m_yDirection < 0)
                        {
                            // inverte a direcao desta bola em X
                            m_xDirection *= -1;
                            m_Vel.X *= -1;

                            // inverte a direcao da bola que colidiu em X
                            ball.m_xDirection *= -1;
                            ball.m_Vel.X *= -1;                            
                        }
                        else // as bolas então em direcoes opostas em Y
                        {
                            // inverte a direcao desta bola em Y
                            //m_yDirection *= -1;
                            //m_Vel.Y *= -1;

                            Vector2 versor1 = (m_Pos - ball.m_Pos) / Vector2.Distance(ball.m_Pos, m_Pos);
                            versor1 *= 1.0f;

                            Vector2 versor2 = (ball.m_Pos - m_Pos) / Vector2.Distance(m_Pos, ball.m_Pos);
                            versor2 *= -1.0f;

                            ball.m_Vel *= versor1;
                            m_Vel *= versor2;
                            
                            // inverte a direcao da bola que colidiu em Y
                            //ball.m_yDirection *= -1;
                            //ball.m_Vel.Y *= -1;                            
                        }

                        return true;
                    }
                }
            }

            return false;
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            base.Draw(gameTime, spriteBatch);

            if (m_BallState == BallState.Moving)
            {
                drawDebugInfo(gameTime, spriteBatch);
            }
        }

        // imprime o tempo restante do jogo
        protected void drawDebugInfo(GameTime gameTime, SpriteBatch spriteBatch)
        {
            StringUtils.DrawString(m_Game.m_Font, spriteBatch, "Vel.X:" + ((int)m_Vel.X).ToString(), 0, 20);
            StringUtils.DrawString(m_Game.m_Font, spriteBatch, "Vel.Y:" + ((int)m_Vel.Y).ToString(), 0, 40);
        }
    }
}